package com.hc.java.pkcs.rsa;

import org.apache.commons.io.FileUtils;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;

/**
 * @author : Henry
 * {@code CreateTime}: 2025-08-27 22:03
 * {@code Version}: 1.0
 */
public class RSADemo {
    public static void main(String[] args) throws Exception {
        // 原文
        String input = "张三丰";
        // 创建密钥对
        // KeyPairGenerator: 密钥对生成器
        String algorithm = "RSA";

        // 生成密钥到文件
        generateKeyToFile(algorithm, "a.pub", "a.pri");
        PrivateKey privateKey = getPrivateKey("a.pri", algorithm);
        PublicKey publicKey = getPublicKey("a.pub", algorithm);
//        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(algorithm);
//        // 生成密钥对
//        KeyPair keyPair = keyPairGenerator.generateKeyPair();
//        // 生成私钥
//        PrivateKey privateKey = keyPair.getPrivate();
//        // 生成公钥
//        PublicKey publicKey = keyPair.getPublic();
        String encrypted = encryptRSA(algorithm, publicKey, input);
        String res = decryptRSA(algorithm, privateKey, encrypted);
        System.out.println("密文：" + encrypted);
        System.out.println("明文：" + res);
    }

    /**
     * @param pubPath   公钥路径
     * @param algorithm 算法
     * @return 公钥
     * @throws IOException
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeySpecException
     */
    public static PublicKey getPublicKey(String pubPath, String algorithm) throws IOException, NoSuchAlgorithmException, InvalidKeySpecException {
        String publicKeyStr = FileUtils.readFileToString(new File(pubPath), Charset.defaultCharset());
        // 创建 key 工厂
        KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(Base64.getDecoder().decode(publicKeyStr));
        return keyFactory.generatePublic(keySpec);
    }

    /**
     * 读取私钥
     *
     * @param priPath   私钥路径
     * @param algorithm 算法
     * @return 返回私钥对象
     * @throws IOException
     */
    public static PrivateKey getPrivateKey(String priPath, String algorithm) throws IOException, NoSuchAlgorithmException, InvalidKeySpecException {
        String privateKeyStr = FileUtils.readFileToString(new File(priPath), Charset.defaultCharset());
        // 创建 key 工厂
        KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKeyStr));
        return keyFactory.generatePrivate(keySpec);
    }

    private static String decryptRSA(String algorithm, Key publicKey, String encrypted) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {

        // 创建加密对象
        Cipher cipher = Cipher.getInstance(algorithm);
        // 解密
        cipher.init(Cipher.DECRYPT_MODE, publicKey);
        // 私钥解密失败
//        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        byte[] decode = Base64.getDecoder().decode(encrypted);
        byte[] decryptedData = cipher.doFinal(decode);
        String decryptedDataStr = new String(decryptedData);
//        System.out.println("decryptedDataStr: " + decryptedDataStr);
        return decryptedDataStr;
    }

    /**
     * 使用密钥加密数据
     *
     * @param algorithm  算法
     * @param privateKey 密钥
     * @param input      原文
     * @return 密文
     * @throws Exception
     */
    public static String encryptRSA(String algorithm, Key privateKey, String input) throws Exception {

        // 创建加密对象
        Cipher cipher = Cipher.getInstance(algorithm);
        // 对加密进行初始化
        // param1: 加密模式
        // param2: 公钥或私钥
        cipher.init(Cipher.ENCRYPT_MODE, privateKey);
        // 加密数据
//        byte[] data = "Hello, world!".getBytes();
        byte[] data = input.getBytes();
        byte[] encryptedData = cipher.doFinal(data);
        // Base64编码
        String encryptedDataBase64 = Base64.getEncoder().encodeToString(encryptedData);
//        System.out.println("encryptedDataBase64: " + encryptedDataBase64);
        return encryptedDataBase64;
    }

    /**
     * 生成密钥对并保存到文件中
     *
     * @param algorithm  算法
     * @param pubKeyPath 公钥文件路径
     * @param priKeyPath 私钥文件路径
     * @throws NoSuchAlgorithmException
     */
    private static void generateKeyToFile(String algorithm, String pubKeyPath, String priKeyPath) throws NoSuchAlgorithmException, IOException {
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(algorithm);
        // 生成密钥对
        KeyPair keyPair = keyPairGenerator.generateKeyPair();
        // 生成私钥
        PrivateKey privateKey = keyPair.getPrivate();
        // 生成公钥
        PublicKey publicKey = keyPair.getPublic();
        // 获取私钥字节数组
        byte[] privateKeyBytes = privateKey.getEncoded();
        // 获取公钥字节数组
        byte[] publicKeyBytes = publicKey.getEncoded();
        // Base64编码
        String privateKeyBase64 = Base64.getEncoder().encodeToString(privateKeyBytes);
        String publicKeyBase64 = Base64.getEncoder().encodeToString(publicKeyBytes);
//        System.out.println("privateKeyBase64: " + privateKeyBase64);
//        System.out.println("publicKeyBase64: " + publicKeyBase64);

        FileUtils.writeStringToFile(new File(pubKeyPath), publicKeyBase64, StandardCharsets.UTF_8);
        FileUtils.writeStringToFile(new File(priKeyPath), privateKeyBase64, StandardCharsets.UTF_8);
    }
}
